﻿//
// Copyright (c) 2011 Canyala Innovation AB
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 
// associated documentation files (the "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
// copies of the Software, and to permit persons to whom the Software is furnished to do so, 
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 
// NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH 
// THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
//

using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Microsoft.VisualStudio.TestTools.UnitTesting;

using Canyala.Lagoon.Extensions;
using Canyala.Lagoon.Functional;
using Canyala.Lagoon.Reflection;

namespace Canyala.Lagoon.Tests
{
    [TestClass]
    public class ReflectionExtensionsTest
    {
        #region - Test data -

        internal class SomeAttribute : Attribute
        {
            public SomeAttribute() { }
        }

        internal class SomeClass
        {
            [Some]
            public string Property { get; set; }
        }

        internal class OtherAttribute : Attribute
        {
            public OtherAttribute() { }
        }

        internal class OtherClass
        {
            [Some][Other]
            public string Property { get; set; }
        }

        #endregion

        [TestMethod]
        public void Given_some_class_with_1_property_and_some_custom_attribute_When_accessing_some_attributes_Then_count_of_some_attributes_be_1()
            { Assert.AreEqual(1, typeof(SomeClass).GetProperties().Single().GetCustomAttributes<SomeAttribute>().Count()); }

        [TestMethod]
        public void Given_other_class_with_1_property_and_2_different_custom_attributes_When_accessing_some_attributes_of_a_type_Then_count_of_attributes_be_1()
            { Assert.AreEqual(1, typeof(OtherClass).GetProperties().Single().GetCustomAttributes<SomeAttribute>().Count()); }

        [TestMethod]
        public void Given_a_class_with_3_properties_When_enumerating_semantic_properties_Then_the_sequence_should_have_a_count_of_3()
            { Assert.AreEqual(3, typeof(Person).GetSemanticProperties().Count()); }

        [TestMethod]
        public void Given_a_class_with_3_properties_and_another_class_with_at_least_3_identical_properties_When_intersecting_semantic_properties_Then_count_of_intersection_should_be_3()
            { Assert.AreEqual(3, typeof(Person).GetSemanticProperties().Intersect(typeof(SomeOtherPerson).GetSemanticProperties()).Count()); }


        #region DeepCopy

        #region - Test Data -
        public class Person
        {
            public static Person Empty = new Person();

            public string Name { get; set; }
            public int Age { get; set; }

            public IEnumerable<Phone> PhoneNumbers { get; set; }

            public Person()
            {
                PhoneNumbers = new List<Phone>();
                Name = string.Empty;
            }
        }

        public class SomeOtherPerson
        {
            public static Person Empty = new Person();

            public string Name { get; set; }
            public int Age { get; set; }
            public string SocialSecurityNumber { get;set;}

            public IEnumerable<Phone> PhoneNumbers { get; set; }

            public SomeOtherPerson()
            {
                PhoneNumbers = new List<Phone>();
                Name = string.Empty;
                SocialSecurityNumber = string.Empty;
            }
        }

        public class Phone
        {
            public static Phone Empty = new Phone();

            public string Number { get; set; }

            public Phone()
            {
                Number = string.Empty;
            }
        }

        static readonly Person PersonA = new Person { Age = 12, Name = "Pelle Karlsson", PhoneNumbers = Seq.Make<Phone>(10) };
        static readonly Person PersonB = new Person { Age = 12, Name = "Peter Karlsson", PhoneNumbers = Seq.Make<Phone>(9) };

        static readonly SomeOtherPerson SomeOtherPersonA = new SomeOtherPerson { Age = 12, Name = "Pelle Karlsson", PhoneNumbers = Seq.Make<Phone>(10) };
        static readonly SomeOtherPerson SomeOtherPersonB = new SomeOtherPerson { Age = 12, Name = "Peter Karlsson", PhoneNumbers = Seq.Make<Phone>(9) };

            
        #endregion

        [TestMethod]
        public void Given_a_person_When_calling_semanticcopy_Then_returns_a_new_identical_person()
        {
            Assert.AreEqual(true, (new SomeOtherPerson()).SemanticCopy(PersonA).SemanticEquals(PersonA));
        }
        
        [TestMethod]
        public void Given_a_person_with_10_phonenumbers_When_calling_semanticcopy_Then_returns_a_new_identical_person()
        {
            Assert.AreEqual(true, Seq.Make<SomeOtherPerson>()
                .PhoneNumbers
                .SemanticCopy(PersonA.PhoneNumbers)
                .SemanticEquals(PersonA.PhoneNumbers));
        }

        [TestMethod]
        public void Given_two_different_persons_of_the_same_type_When_semantically_compared_Then_comparison_should_return_false()
        {
            Assert.AreEqual(false, PersonA.SemanticEquals(PersonB));
        }



        #endregion
    }
}
